<?php
/**
 * Ly - 系统函数库
 *
 * 系统函数，不可独立于系统本身环境运行，需要Ly系统环境的支持
 *
 * Copyright (c) 2013 YinHailin All rights reserved.
 * @Author: YinHailin
 * @Authorize: Boren Network
 * @Created by YinHailin at 2013-11-01
 */

defined('LY_VERSION') or exit();

/*
 * 404处理 
 * 调试模式会抛异常 
 * 部署模式下面传入url参数可以指定跳转页面，否则发送404信息
 * @param string $msg 提示信息
 * @param string $url 跳转URL地址
 */
function _404($msg='', $url='') {
  header("Content-Type:text/html; charset=".C('DEFAULT_CHARSET'));
  APP_DEBUG && exit($msg);
  if (empty($url) && C('URL_404_REDIRECT')) {
    $url = C('URL_404_REDIRECT');
  }
  if ($url) {
    redirect($url);
  } else {
    send_http_status(404);
    exit;
  }
}

/*
 * 创建项目目录结构
 */
function build_app_dir() {
  //没有创建项目目录则自动创建
  if (!is_dir(APP_PATH)) mkdir(APP_PATH, 0755, true);
  if (is_writeable(APP_PATH)) {
    $dirs = array(
      LIB_PATH,
      TPL_PATH,
    );
    foreach ($dirs as $dir){
      if (!is_dir($dir)) mkdir($dir, 0755, true);
    }
    //写入目录安全文件
    build_dir_secure($dirs);
  } else {
    header('Content-Type:text/html; charset=utf-8');
    exit('~项目目录不可写，目录无法自动生成！<BR>请使用项目生成器或者手动生成项目目录~');
  }
}

/*
 * 生成目录安全文件
 */
function build_dir_secure($dirs = '') {
  //目录安全写入
  if (defined('BUILD_DIR_SECURE') && BUILD_DIR_SECURE) {
    //自动写入目录安全文件
    $content = DIR_SECURE_CONTENT;
    $files = explode(',', DIR_SECURE_FILENAME);
    foreach ($files as $filename) {
      foreach ($dirs as $dir) {
        file_put_contents($dir.$filename, $content);
      }
    }
  }
}

/*
 * 创建系统目录结构
 */
function build_sys_dir() {
  //没有创建系统目录则自动创建
  if (is_writeable(ROOT_PATH)) {
    $dirs = array(
      RUNTIME_PATH,
      CONF_PATH,
      EXTEND_PATH,
      PLUGIN_PATH,
    );
    foreach ($dirs as $dir){
      if (!is_dir($dir)) mkdir($dir, 0755, true);
    }
    //写入目录安全文件
    build_dir_secure($dirs);
    //写入初始配置文件
    if (!is_file(CONF_PATH.'Config.conf.php')) {
      file_put_contents(CONF_PATH.'Config.conf.php', "<?php\nreturn array(\n\t//'配置项'=>'配置值'\n);");
    }
  } else {
    header('Content-Type:text/html; charset=utf-8');
    exit('~根目录不可写，目录无法自动生成！<BR>请使用项目生成器或者手动生成系统目录~');
  }
}

/*
 * 检查缓存目录(Runtime) 如果不存在则自动创建
 */
function check_runtime() {
  if (!is_dir(RUNTIME_PATH)) {
    mkdir(RUNTIME_PATH, 0777, true);
  } elseif (!is_writeable(RUNTIME_PATH)) {
    header('Content-Type:text/html; charset=utf-8');
    exit('目录 [ '.RUNTIME_PATH.' ] 不可写！');
  }
}

/*
 * 区分大小写的文件存在判断
 * @param string $filename 文件地址
 * @return boolean
 */
function file_exists_case($filename) {
  if (is_file($filename)) {
    if (IS_WIN && C('APP_FILE_CASE')) {
      if (basename(realpath($filename)) != basename($filename))
        return false;
    }
    return true;
  }
  return false;
}

/*
 * 错误输出
 * @param mixed $error 错误
 */
function halt($errMessage, $errFile, $errLine) {
  if (APP_DEBUG) {
    //调试模式下输出错误信息
    shutdown('系统错误', $errMessage, $errFile, $errLine);
  } else {
    //非调试模式下输出友好信息
    shutdown();
  }
  exit;
}

/*
 * 导入所需的类库,本函数有缓存功能
 * @param string $class 类库命名空间字符串
 * @param string $baseUrl 起始路径
 * @param string $ext 导入的文件扩展名
 * @return boolean
 */
function import($class, $baseUrl = '', $ext = '.class.php') {
  static $_file = array();
  $class = str_replace(array('.', '#'), array('/', '.'), $class);
  //缓存功能，检查类是否已经加载
  if (isset($_file[$class . $baseUrl])) {
    return true;
  } else {
    $_file[$class . $baseUrl] = true;
  }
  $class_strut = explode('/', $class);
  if (empty($baseUrl)) {
    $libPath = LIB_PATH;
    if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) {
      //加载当前项目应用类库
      $baseUrl = dirname($libPath);
      $class = substr_replace($class, basename($libPath).'/', 0, strlen($class_strut[0]) + 1);
    } elseif ('class' == strtolower($class_strut[0])) {
      //加载扩展类库
      $baseUrl = EXTEND_PATH.'Class/';
      $class = substr($class, 6);
    } else {
      //加载其他项目应用类库
      $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
      $baseUrl = dirname(APP_PATH).'/'.$class_strut[0].'/'.basename($libPath).'/';
    }
  }
  if (substr($baseUrl, -1) != '/') {
    $baseUrl .= '/';
  }
  $classfile = $baseUrl . $class . $ext;
  if (!class_exists(basename($class), false)) {
    //如果类不存在,则导入类库文件
    return require_cache($classfile);
  }
}

/*
 * 加载动态扩展文件
 */
function load_ext_file() {
  //加载自定义外部函数库
  if (C('LOAD_EXT_FUNC')) {
    $funcs = explode(',', C('LOAD_EXT_FUNC'));
    foreach ($funcs as $func) {
      $func = EXTEND_PATH.'Func/'.$func.'.func.php';
      if (is_file($func)) include $func;
    }
  }
  //加载自定义外部类库
  if (C('LOAD_EXT_CLASS')) {
    $classes = explode(',', C('LOAD_EXT_CLASS'));
    foreach ($classes as $class) {
      $class = EXTEND_PATH.'Class/'.$class.'.class.php';
      if (is_file($class)) include $class;
    }
  }
  //加载自定义配置文件
  if (C('LOAD_EXT_CONFIG')) {
    $configs = C('LOAD_EXT_CONFIG');
    if (is_string($configs)) $configs = explode(',', $configs);
    foreach ($configs as $key=>$config){
      $file = CONF_PATH.$config.'.conf.php';
      if (is_file($file)) {
        is_numeric($key) ? C(include $file) : C($key, include $file);
      }
    }
  }
}

/*
 * URL重定向
 * @param string $url 重定向的URL地址
 * @param integer $time 重定向的等待时间（秒）
 * @param string $msg 重定向前的提示信息
 */
function redirect($url, $time = 0, $msg = '') {
  //多行URL地址支持
  $url = str_replace(array("\n", "\r"), '', $url);
  if (empty($msg)) {
    $msg = "系统将在{$time}秒之后自动跳转到{$url}！";
  }
  if (!headers_sent()) {
    //redirect
    if (0 === $time) {
      header('Location: ' . $url);
    } else {
      header("Content-Type:text/html; charset=".C('DEFAULT_CHARSET'));
      header("refresh:{$time};url={$url}");
      echo($msg);
    }
    exit();
  } else {
    $str = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
    if ($time != 0) {
      $str .= $msg;
    }
    exit($str);
  }
}

/*
 * 批量导入文件,成功则返回
 * @param array $array 文件数组
 * @param boolean $return 加载成功后是否立即返回，不再继续加载
 * @return boolean
 */
function require_array($array, $return=false){
  foreach ($array as $file){
    if (require_cache($file) && $return) return true;
  }
  if ($return) return false;
}

/*
 * 优化的require_once
 * @param string $filename 文件地址
 * @return boolean
 */
function require_cache($filename) {
  static $_importFiles = array();
  if (!isset($_importFiles[$filename])) {
    if (file_exists_case($filename)) {
      require $filename;
      $_importFiles[$filename] = true;
    } else {
      $_importFiles[$filename] = false;
    }
  }
  return $_importFiles[$filename];
}

/*
 * 取得对象实例 支持调用类的静态方法
 * @param string $name 类名
 * @param string $method 方法名，如果为空则返回实例化对象
 * @param array $args 调用参数
 * @return object
 */
function get_instance_of($name, $method='', $args=array()) {
  static $_instance = array();
  $identifier = empty($args) ? $name . $method : $name . $method . to_guid_string($args);
  if (!isset($_instance[$identifier])) {
    if (class_exists($name)) {
      $o = new $name();
      if (method_exists($o, $method)) {
        if (!empty($args)) {
          $_instance[$identifier] = call_user_func_array(array(&$o, $method), $args);
        } else {
          $_instance[$identifier] = $o->$method();
        }
      } else {
        $_instance[$identifier] = $o;
      }
    } else {
      halt('目标类不存在 : ' . $name, __FILE__, __LINE__);
    }
  }
  return $_instance[$identifier];
}

/*
 * 清空页面输出错误信息，并终止程序执行
 * @param string $errType 错误号
 * @param string $errMessage 错误信息
 * @param string $errFile 错误文件
 * @param string $errLine 错误行号
 */
function shutdown($errType = '', $errMessage = '', $errFile = '', $errLine = '') {
  ob_end_clean();
  include C('TEMP_EXCEPTION_FILE');
  exit();
}

/*
 * 配置数据为|1,|2,|3,样式
 * @param array $array 字符串
 * @return string
 */
function set_config($array) {
  $string = implode(',|', $array);
  if ($string != '') { $string = '|'.$string.',';}
  return $string;
}